package com.yc.cloud.admin.service.impl;

import cn.hutool.json.JSONUtil;
import com.yc.cloud.admin.config.MediaKitApiProperties;
import com.yc.cloud.admin.dto.RecordingConfig;
import com.yc.cloud.admin.dto.request.MediaKitRecordReqDTO;
import com.yc.cloud.admin.dto.response.IsRecordingResponse;
import com.yc.cloud.admin.dto.response.MediaListResponse;
import com.yc.cloud.admin.dto.response.RecordResponse;
import com.yc.cloud.admin.dto.response.SnapResponse;
import com.yc.cloud.admin.service.FFmpegStreamService;
import com.yc.cloud.admin.service.MediaKitApiService;
import com.yc.cloud.admin.vo.MediaStreamVo;
import com.yc.cloud.entity.HwCamera;
import com.yc.cloud.mapper.HwCameraMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.client.WebClient;

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Map;

/**
 * MediaKit API 服务实现类
 * 
 * @author kinggu
 * @since 2025-01-XX
 */
@Slf4j
@Service
public class MediaKitApiServiceImpl implements MediaKitApiService {

    @Resource
    private MediaKitApiProperties mediaKitApiProperties;

    @Resource(name = "mediaKitWebClient")
    private WebClient mediaKitWebClient;
    
    @Resource
    private FFmpegStreamService ffmpegStreamService;

    @Resource
    private HwCameraMapper hwCameraMapper;

    @Override
    public boolean startRecord(MediaKitRecordReqDTO reqDTO) {
        // 先检查是否正在录制
        if (isRecord(reqDTO)) {
            log.warn("流已在录制中，无需重复开始录制: stream={}", reqDTO.getStream());
            return true; // 已在录制中，返回成功
        }
        
        // 检查流是否可用
        if (!ffmpegStreamService.checkStreamAvailable(reqDTO.getStream())) {
            log.error("流不可用，无法开始录制: stream={}", reqDTO.getStream());
            return false;
        }
        
        try {
            MediaKitApiProperties.RecordConfig recordConfig = mediaKitApiProperties.getRecord();
            
            String responseBody = mediaKitWebClient.get()
                    .uri(uriBuilder -> uriBuilder
                            .path("/index/api/startRecord")
                            .queryParam("secret", mediaKitApiProperties.getSecret())
                            .queryParam("type", recordConfig.getType())
                            .queryParam("vhost", recordConfig.getVhost())
                            .queryParam("app", recordConfig.getApp())
                            .queryParam("stream", reqDTO.getStream())
                            // .queryParam("customized_path", recordConfig.getCustomizedPath())
                            .build())
                    .retrieve()
                    .bodyToMono(String.class)
                    .timeout(Duration.ofSeconds(10))
                    .block();
            
            if (responseBody != null) {
                RecordResponse response = JSONUtil.toBean(responseBody, RecordResponse.class);
                if (response.isSuccess()) {
                    log.info("开始录制流成功: stream={}", reqDTO.getStream());
                    return true;
                } else {
                    log.error("开始录制流失败: stream={}, code={}, msg={}", reqDTO.getStream(), response.getCode(), response.getMsg());
                }
            } else {
                log.error("开始录制流请求失败: stream={}, 响应为空", reqDTO.getStream());
            }
        } catch (Exception e) {
            log.error("开始录制流异常: stream={}", reqDTO.getStream(), e);
        }
            return false;
    }

    @Override
    public boolean stopRecord(MediaKitRecordReqDTO reqDTO) {
        try {
            MediaKitApiProperties.RecordConfig recordConfig = mediaKitApiProperties.getRecord();
            
            String responseBody = mediaKitWebClient.get()
                    .uri(uriBuilder -> uriBuilder
                            .path("/index/api/stopRecord")
                            .queryParam("secret", mediaKitApiProperties.getSecret())
                            .queryParam("type", recordConfig.getType())
                            .queryParam("vhost", recordConfig.getVhost())
                            .queryParam("app", recordConfig.getApp())
                            .queryParam("stream", reqDTO.getStream())
                            .build())
                    .retrieve()
                    .bodyToMono(String.class)
                    .timeout(Duration.ofSeconds(10))
                    .block();
            
            if (responseBody != null) {
                RecordResponse response = JSONUtil.toBean(responseBody, RecordResponse.class);
                if (response.isSuccess()) {
                    log.info("停止录制流成功: stream={}", reqDTO.getStream());
                    return true;
                } else {
                    log.error("停止录制流失败: stream={}, code={}, msg={}", reqDTO.getStream(), response.getCode(), response.getMsg());
                }
            } else {
                log.error("停止录制流请求失败: stream={}, 响应为空", reqDTO.getStream());
            }
        } catch (Exception e) {
            log.error("停止录制流异常: stream={}", reqDTO.getStream(), e);
        }
            return false;
    }

    @Override
    public List<MediaStreamVo> getMediaList() {
        try {
            MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
            params.add("secret", mediaKitApiProperties.getSecret());
            
            String responseBody = mediaKitWebClient.post()
                    .uri("/index/api/getMediaList")
                    .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                    .bodyValue(params)
                    .retrieve()
                    .bodyToMono(String.class)
                    .timeout(Duration.ofSeconds(10))
                    .block();
            
            if (responseBody != null) {
                MediaListResponse response = JSONUtil.toBean(responseBody, MediaListResponse.class);
                
                if (response.isSuccess() && response.getData() != null) {
                    log.info("获取流媒体列表成功，共{}个流", response.getData().size());
                    return convertToMediaStreamVoList(response.getData());
                } else {
                    log.error("获取流媒体列表失败: code={}, msg={}", response.getCode(), response.getMsg());
                }
            } else {
                log.error("获取流媒体列表请求失败: 响应为空");
            }
        } catch (Exception e) {
            log.error("获取流媒体列表异常", e);
        }
        return new ArrayList<>();
    }

    /**
     * 获取截图
     * 
     * @param url 需要截图的url
     * @return 截图的base64数据或URL
     */
    @Override
    public String getSnap(String url) {
        try {
            // 固定超时参数：截图失败时间10秒，过期时间30秒
            final int timeoutSec = 10;
            final int expireSec = 30;
            
            String responseBody = mediaKitWebClient.get()
                    .uri(uriBuilder -> uriBuilder
                            .path("/index/api/getSnap")
                            .queryParam("secret", mediaKitApiProperties.getSecret())
                            .queryParam("url", url)
                            .queryParam("timeout_sec", timeoutSec)
                            .queryParam("expire_sec", expireSec)
                            .build())
                    .retrieve()
                    .bodyToMono(String.class)
                    .timeout(Duration.ofSeconds(30)) // 截图可能需要更长时间
                    .block();
                    
                        if (responseBody != null) {
                // 检查响应是否为JSON格式（错误响应或成功响应）
                if (responseBody.startsWith("{")) {
                    SnapResponse response = JSONUtil.toBean(responseBody, SnapResponse.class);
                    if (response.isSuccess()) {
                        log.info("获取截图成功（JSON格式）: url={}", url);
                        // 保存base64图片数据到本地
                        String savedPath = saveImageToLocal(response.getData(), true);
                        log.info("截图已保存到: {}", savedPath);
                        return response.getData(); // 返回base64编码的图片数据
                    } else {
                        log.error("获取截图失败: url={}, code={}, msg={}", url, response.getCode(), response.getMsg());
                        return null;
                    }
                } else {
                    // 如果不是JSON，说明直接返回的是图片数据
                    log.info("获取截图成功（直接返回图片数据）: url={}", url);
                    // 保存图片数据到本地
                    String savedPath = saveImageToLocal(responseBody, false);
                    log.info("截图已保存到: {}", savedPath);
                    return responseBody;
                }
            } else {
                log.error("获取截图请求失败: url={}, 响应为空", url);
            }
                } catch (Exception e) {
            log.error("获取截图异常: url={}", url, e);
        }
        return null;
    }

    /**
     * 转换 MediaInfo 列表为 MediaStreamVo 列表
     */
    private List<MediaStreamVo> convertToMediaStreamVoList(List<MediaListResponse.MediaInfo> mediaInfoList) {
        List<MediaStreamVo> streamList = new ArrayList<>();
        
        for (MediaListResponse.MediaInfo mediaInfo : mediaInfoList) {
        try {
            MediaStreamVo streamVo = new MediaStreamVo();
            
            // 基本信息
                streamVo.setApp(mediaInfo.getApp());
                streamVo.setStream(mediaInfo.getStream());
                streamVo.setVhost(mediaInfo.getVhost());
                streamVo.setSchema(mediaInfo.getSchema());
                
                // 流媒体统计信息
                streamVo.setReaderCount(mediaInfo.getReaderCount());
                streamVo.setTotalReaderCount(mediaInfo.getTotalReaderCount());
                streamVo.setOriginType(mediaInfo.getOriginType());
                streamVo.setOriginTypeStr(mediaInfo.getOriginTypeStr());
                streamVo.setOriginUrl(mediaInfo.getOriginUrl());
                streamVo.setCreateStamp(mediaInfo.getCreateStamp());
                streamVo.setAliveSecond(mediaInfo.getAliveSecond());
                streamVo.setBytesSpeed(mediaInfo.getBytesSpeed());
            
            // 音视频轨道信息
                if (mediaInfo.getTracks() != null && !mediaInfo.getTracks().isEmpty()) {
                    streamVo.setTrackCount(mediaInfo.getTracks().size());
                    // 将轨道信息转换为JSON字符串存储
                    streamVo.setTracksJson(JSONUtil.toJsonStr(mediaInfo.getTracks()));
                }
                
                // 网络连接信息
                if (mediaInfo.getOriginSock() != null) {
                    // 将 OriginSock 对象转换为 Map
                    streamVo.setOriginSock(JSONUtil.parseObj(JSONUtil.toJsonStr(mediaInfo.getOriginSock())));
                }
                
                streamList.add(streamVo);
        } catch (Exception e) {
                log.warn("转换流媒体数据失败: mediaInfo={}", mediaInfo, e);
                // 单个数据转换失败不影响整体处理，继续处理下一个
            }
        }
        
        return streamList;
    }

    /**
     * 保存图片数据到本地文件
     * 
     * @param imageData 图片数据
     * @param isBase64 是否为base64编码
     * @return 保存的文件路径
     */
    private String saveImageToLocal(String imageData, boolean isBase64) {
        try {
            // 创建保存目录
            String saveDir = "temp/mediakit_snapshots";
            Path dirPath = Paths.get(saveDir);
            if (!Files.exists(dirPath)) {
                Files.createDirectories(dirPath);
            }
            
            // 生成文件名
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss_SSS"));
            String fileName = "snap_" + timestamp + ".jpg";
            String filePath = saveDir + "/" + fileName;
            
            // 保存文件
            if (isBase64) {
                // Base64解码后保存
                byte[] imageBytes = Base64.getDecoder().decode(imageData);
                try (FileOutputStream fos = new FileOutputStream(filePath)) {
                    fos.write(imageBytes);
                }
                log.info("Base64图片数据已保存，大小: {} bytes", imageBytes.length);
            } else {
                // 直接保存字符串数据（可能是二进制数据的字符串表示）
                try (FileOutputStream fos = new FileOutputStream(filePath)) {
                    fos.write(imageData.getBytes());
                }
                log.info("原始图片数据已保存，大小: {} bytes", imageData.getBytes().length);
            }
            
            return filePath;
        } catch (IOException e) {
            log.error("保存图片到本地失败", e);
            return null;
        }
    }

    @Override
    public boolean isRecord(MediaKitRecordReqDTO reqDTO) {
        try {
            MediaKitApiProperties.RecordConfig recordConfig = mediaKitApiProperties.getRecord();
            
            String responseBody = mediaKitWebClient.get()
                    .uri(uriBuilder -> uriBuilder
                            .path("/index/api/isRecording")
                            .queryParam("secret", mediaKitApiProperties.getSecret())
                            .queryParam("type", recordConfig.getType())
                            .queryParam("vhost", recordConfig.getVhost())
                            .queryParam("app", recordConfig.getApp())
                            .queryParam("stream", reqDTO.getStream())
                            .build())
                    .retrieve()
                    .bodyToMono(String.class)
                    .timeout(Duration.ofSeconds(10))
                    .block();
            
            if (responseBody != null) {
                IsRecordingResponse response = JSONUtil.toBean(responseBody, IsRecordingResponse.class);
                if (response.isSuccess()) {
                    log.info("查询录制状态成功: stream={}, isRecording={}", reqDTO.getStream(), response.isRecording());
                    return response.isRecording();
                } else {
                    log.error("查询录制状态失败: stream={}, code={}, msg={}", reqDTO.getStream(), response.getCode(), response.getMsg());
                }
            } else {
                log.error("查询录制状态请求失败: stream={}, 响应为空", reqDTO.getStream());
            }
        } catch (Exception e) {
            log.error("查询录制状态异常: stream={}", reqDTO.getStream(), e);
        }
        return false; // 出错时默认认为未在录制
    }

    @Override
    public boolean startRecording(Long cameraId, RecordingConfig config) {
        log.info("为摄像头 {} 开始录制", cameraId);
        
        try {
            // 根据摄像头ID获取流信息
            HwCamera camera = hwCameraMapper.selectById(cameraId);
            if (camera == null) {
                log.error("摄像头不存在: cameraId={}", cameraId);
                return false;
            }
            
            String streamId = extractStreamId(camera.getStreamUrl());
            if (streamId == null) {
                log.error("无法从摄像头获取流ID: cameraId={}, streamUrl={}", cameraId, camera.getStreamUrl());
                return false;
            }
            
            // 构造录制请求
            MediaKitRecordReqDTO reqDTO = new MediaKitRecordReqDTO();
            reqDTO.setStream(streamId);
            
            return startRecord(reqDTO);
            
        } catch (Exception e) {
            log.error("为摄像头 {} 开始录制异常", cameraId, e);
            return false;
        }
    }

    @Override
    public boolean stopRecording(Long cameraId) {
        log.info("为摄像头 {} 停止录制", cameraId);
        
        try {
            // 根据摄像头ID获取流信息
            HwCamera camera = hwCameraMapper.selectById(cameraId);
            if (camera == null) {
                log.error("摄像头不存在: cameraId={}", cameraId);
                return false;
            }
            
            String streamId = extractStreamId(camera.getStreamUrl());
            if (streamId == null) {
                log.error("无法从摄像头获取流ID: cameraId={}, streamUrl={}", cameraId, camera.getStreamUrl());
                return false;
            }
            
            // 构造录制请求
            MediaKitRecordReqDTO reqDTO = new MediaKitRecordReqDTO();
            reqDTO.setStream(streamId);
            
            return stopRecord(reqDTO);
            
        } catch (Exception e) {
            log.error("为摄像头 {} 停止录制异常", cameraId, e);
            return false;
        }
    }

    /**
     * 从流URL中提取流ID
     * 根据实际的URL格式进行解析
     */
    private String extractStreamId(String streamUrl) {
        if (streamUrl == null || streamUrl.trim().isEmpty()) {
            return null;
        }
        
        try {
            // 处理不同格式的流URL
            // 例如: rtmp://server/app/stream -> stream
            // 或者: webrtc://server/app/stream -> stream
            // 或者直接就是stream ID
            
            if (streamUrl.contains("/")) {
                String[] parts = streamUrl.split("/");
                return parts[parts.length - 1]; // 取最后一部分作为stream ID
            } else {
                return streamUrl; // 直接就是stream ID
            }
            
        } catch (Exception e) {
            log.error("解析流URL失败: streamUrl={}", streamUrl, e);
            return null;
        }
    }

    @Override
    public Map<String, Object> getServerConfig(String secret) {
        log.info("获取MediaKit服务器配置");
        
        try {
            MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
            if (secret != null && !secret.trim().isEmpty()) {
                formData.add("secret", secret);
            }
            
            Map response = mediaKitWebClient.post()
                    .uri("/index/api/getServerConfig")
                    .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                    .bodyValue(formData)
                    .retrieve()
                    .bodyToMono(Map.class)
                    .timeout(Duration.ofSeconds(10))
                    .block();
            
            if (response != null) {
                log.info("成功获取MediaKit服务器配置");
                return response;
            } else {
                log.error("获取MediaKit服务器配置失败: 响应为空");
                return null;
            }
            
        } catch (Exception e) {
            log.error("获取MediaKit服务器配置异常", e);
            return null;
        }
    }

    @Override
    public Map<String, Object> setServerConfig(String secret, Map<String, String> configs) {
        log.info("设置MediaKit服务器配置: {}", configs);
        
        try {
            MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
            
            // 添加secret参数
            if (secret != null && !secret.trim().isEmpty()) {
                formData.add("secret", secret);
            }
            
            // 添加所有配置项
            if (configs != null && !configs.isEmpty()) {
                configs.forEach(formData::add);
            }
            
            @SuppressWarnings("unchecked")
            Map<String,Object> response = mediaKitWebClient.post()
                    .uri("/index/api/setServerConfig")
                    .contentType(MediaType.APPLICATION_FORM_URLENCODED)
                    .bodyValue(formData)
                    .retrieve()
                    .bodyToMono(Map.class)
                    .timeout(Duration.ofSeconds(10))
                    .block();
            
            if (response != null) {
                log.info("成功设置MediaKit服务器配置: {}", response);
                return response;
            } else {
                log.error("设置MediaKit服务器配置失败: 响应为空");
                return null;
            }
            
        } catch (Exception e) {
            log.error("设置MediaKit服务器配置异常", e);
            return null;
        }
    }
}